#!/bin/bash

### BEGIN INIT INFO
# Provides:		  6rd
# Required-Start:	$network
# Required-Stop:	 $network
# Default-Start:	 2 3 4 5
# Default-Stop:	  0 1 6
# Short-Description: 6RD Configuration Script
# Description:	   Bring up/down 6RD interface
### END INIT INFO

# /etc/init.d/6rd
###############################################################################
# 6rd : Script to start / stop 6rd IPv6
#
# Changelog:
# Version 1.0rc5 (20101127) : First release ...
###############################################################################

# Some things that run always
touch /var/lock/6rd
ipfile="/tmp/ipv4.txt"

# Global Variables
# WARNING : the script will accept only 6RD prefixes sizes 24,28,32.
glob_6rd_net="2a02:1200::/28"	# 6RD prefix of your ISP. They provide it to you.
glob_6rd_br="164.128.155.23"	# 6RD Anycast BR of your ISP.
glob_6rd_iface="6rdtun"			# Name of the interface for the 6rd tunnel

# Interfaces. They can be the same if this box is not routing ipv4.
glob_lan_iface="eth0.10"		# Your LAN IPv4/6 interface
glob_wan_iface="eth0.20"		# Your WAN IPv4 interface

# implements startup of 6rd
start() {

	# Need to get my ip automatically. I use whatismyip.org's automation page
	wget --output-document=$ipfile http://whatismyip.org

	# Maths and String part ... funny stuff !
	# Check that the prefix is supported		
	ipv6_6rd_mask=$(echo $glob_6rd_net | cut -f 2 -d "/")		
	if [ $ipv6_6rd_mask != 24 -a $ipv6_6rd_mask != 28 -a $ipv6_6rd_mask != 32 ]; then
		echo "6rd : Error : Can't deal with subnet prefixes other than /24, /28, or /32."			
		exit
	fi
	
	# Get our real public IPv4 address.
	ipv4=$(cat $ipfile)
	if [[ ! $ipv4 =~ \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} ]]; then
		sleep 5; # Try again in 5 seconds, then give up
		wget --output-document=$ipfile http://whatismyip.org
		ipv4=$(cat $ipfile)
		if [[ ! $ipv4 =~ \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} ]]; then
			# give up
			echo "6rd : Error : Can't get IPv4 public IP address."
			exit
		fi
	fi

	# IPv4 WAN IPv4 address. Can be either public or private, doesn't matter.
	ipv4_wan				= $(ifconfig $glob_wan_iface | awk '/inet ad?r/ {split ($2,A,":"); print A[2]}')
	
	# From the WAN IPv4 address, we deduct the IPv6 customer prefix.
	ipv6_6rd_prefix 		= ipv4to6rd $ipv4_wan
	
	# The customer prefix is either a /24 or /28 : 1st subnet for tunnel, 2nd for LAN
	# The customer prefix is = /32 : Subnet only the LAN (doesn't work ?)
	ipv6_wan = ipv6subnet $ipv6_6rd_prefix 0x0
	ipv6_lan = ipv6subnet $ipv6_6rd_prefix 0x1
	if [ipv6pfxtomask $ipv6_6rd_prefix == 32]; then
		ipv6_lan = ipv6_wan
	fi
	
#	ipv4_hex 				= ipv4tohex $ipv4_wan
#	ipv6_6rd_prefix 		= ${glob_6rd_net:0:$((1+$ipv6_6rd_mask/4))}
#	pfx_6rd_nocolon 		= $(echo $ipv6_6rd_prefix | tr -d ":")
#	printf -v ipv6_nocolon "%16x" $((0x$pfx_6rd_nocolon*0x10**(16-$ipv6_6rd_mask/4)+0x$ipv4_hex*0x10**(8-$ipv6_6rd_mask/4)))
	ipv6_wan				= ${ipv6_nocolon:0:4}:${ipv6_nocolon:4:4}:${ipv6_nocolon:8:4}:${ipv6_nocolon:12}::1

	# Now deal with the LAN Subnet for $glob_eth_iface
	# This will work in fact only with /28 and /24 ... no idea about /32
	# We in fact just pick up the next /64 in our allocated /60 or /56
	ipv6_eth_lan_nocolon	=	hexto16n 
	ipv6_eth_lan			=	hextoip $ipv6_eth_lan_nocolon 0x1

	# display status
	echo 6rd - PUBLIC IPv4 address is $ipv4_pub
	echo 6rd - PUBLIC IPv6 address is $ipv6_tun
	echo 6rd - $glob_lan_iface IPv6 address is $ipv6_lan

	# echo Configuring...
	# Configure the tunnel
	ip tunnel add $glob_6rd_iface mode sit ttl 64 local $ipv4_wan
	ip tunnel 6rd dev $glob_6rd_iface 6rd-prefix $glob_6rd_net
	ip link set $glob_6rd_iface up
	ip -6 addr add $ipv6_tun/64 dev $glob_6rd_iface

	# Configure the LAN
	ip -6 addr add $ipv6_lan/64 dev $glob_lan_iface
	ip -6 route add 2000::/3 via ::$glob_6rd_br dev 6rdtun

	# Restart RADVD if necessary
	if [ -x /etc/init.d/radvd ]; then
		/etc/init.d/radvd restart
	fi

	# log the realized operation
	logger "IPv6 using 6rd configured (ipv4 public: $ipv4, ipv6: $ipv6)"
}

# stops 6rd and flushes all routes and addresses
stop() {
	/sbin/ip -6 route flush dev 6rdtun
	/sbin/ip -6 route flush scope global
	/sbin/ip -6 addr flush scope global
	/sbin/ip link set dev 6rdtun down
	/sbin/ip tunnel del 6rdtun
}

status() {
	echo "IPV6 STATUS"
	echo "--"
	echo "Addresses"
	echo "---------"
	/sbin/ip -6 addr show
	echo " "
	echo "Routes"
	echo "------"
	/sbin/ip -6 route show
	echo "Neighbors"
	echo "------"
	/sbin/ip -6 neigh show
}

restart() {
		stop
		start
}

function ipv4to6rd {
	# $1 : IPv4 to consider
	# $2 : IPv6 Prefix
	# Will return teh customer 6rd prefix
	
	ipv4_hex 				= ipv4tohex $1	
	ipv6_6rd_mask 			= ipv6pfxtomask $2	
	# Gets the digits from the first digit to the 
	ipv6_6rd_prefix 		= ${2:0:$((1+$ipv6_6rd_mask/4))}
}

function ipv6pfxtomask {
	# $1 : prefix IPv6 (with mask)
	
	ipv6_6rd_mask=$(echo $1 | cut -f 2 -d "/")
	
	return $ipv6_6rd_mask
}

function ipv4tohex {
	# $1 : value of the IPv4 (with dots)
	
	printf -v ipv4 "%02x%02x%02x%02x" $(echo $ipv4 | tr "." " ")
	
	return $ipv4math
}

function hextoip {
	# $1 : value of the 1st 64 bits
	# $2 : value of the last 64 bits
	ipv6_beg = "${1:0:4}:${1:4:4}:${1:8:4}:${1:12}"
	ipv6_end = "${2:0:4}:${2:4:4}:${2:8:4}:${2:12}"
	return $ipv6_beg:$ipv6_end
}

function hexto16n {
	# $1 : math value
	printf -v ipv6_buf "%16x" $1
	return $ipv6_buf
#	printf -v ipv6_eth_lan_nocolon "%16x" $((0x$ipv6_nocolon + 0x1))
}

function ipv6subnet {
	# $1 : IPv6 6rd prefix
	# $2 : increment for the last nibble in the first /64:
	# 2001:db8:0001:000X
	#                  ^ That one

	
	
}

# Carry out specific functions when asked to by the system
case "$1" in
  start)
	echo "Starting script 6rd "
		start
	;;
  stop)
	echo "Stopping script 6rd"
		stop
   ;;
  status)
		status
	;;
  restart)
		restart
		;;
  *)
	echo "Usage: /etc/init.d/6rd {start|stop|restart|status}"
	exit 1
	;;
esac

exit 0

# This is a 3-Clause BSD Licence, GPL-Compatible
# http://www.gnu.org/licenses/license-list.html#ModifiedBSD
# Please be aware that the copyright information MUST be maintained.
#
# (C) Carlos M. Martinez-Cagnazzo, 2008. Original 6to4 Script.
#     http://cagnazzo.name/drupal/6to4
#
# (C) Guillaume Leclanche, 2010. Completed for 6rd and non-NATed routers.
#     guillaume at leclanche.net
#
# Redistribution and use in source and binary forms, with or without 
# modification, are permitted provided that the following conditions are met:
#
# - Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright notice, 
# this list of conditions and the following disclaimer in the documentation 
# and/or other materials provided with the distribution.
# - The names of the authors may not be used to endorse or promote products 
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR  
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.